/**
 * 
 */
package com.googlecode.jstructs.instr;

import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
import static org.objectweb.asm.Opcodes.ACONST_NULL;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.DLOAD;
import static org.objectweb.asm.Opcodes.DSTORE;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.FLOAD;
import static org.objectweb.asm.Opcodes.FSTORE;
import static org.objectweb.asm.Opcodes.GETFIELD;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.ISTORE;
import static org.objectweb.asm.Opcodes.LLOAD;
import static org.objectweb.asm.Opcodes.LSTORE;
import static org.objectweb.asm.Opcodes.MONITORENTER;
import static org.objectweb.asm.Opcodes.MONITOREXIT;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.SIPUSH;
import static org.objectweb.asm.Opcodes.SWAP;
import static org.objectweb.asm.Opcodes.V1_6;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.analysis.Analyzer;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicInterpreter;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.Value;

import com.googlecode.jstructs.ValueType;
import com.googlecode.jstructs.runtime.ValueTypeStack;

final class MethodInstr extends MethodAdapter {
	private static final String VALUE_TYPE_STACK_CLASS = ValueTypeStack.class
			.getName().replace('.', '/');

	final MethodNode mn;
	private Analyzer analyzer;
	private boolean isStatic;
	private JStructClassInstr cv;

	boolean needsInstrumentation;

	// return value flow
	//
	MethodInstr(JStructClassInstr cv, MethodNode mn) {
		super(mn);
		this.isStatic = (mn.access & ACC_STATIC) != 0;
		this.cv = cv;
		this.mn = mn;

	}

	@Override
	public void visitEnd() {
		super.visitEnd();
		cv.methodVisitEnd(this);
	}

	@Override
	public void visitFieldInsn(int opcode, String owner, String name,
			String desc) {
		if (!needsInstrumentation && cv.isValueType(owner))
			needsInstrumentation = true;
		super.visitFieldInsn(opcode, owner, name, desc);
	}

	@Override
	public void visitLocalVariable(String name, String desc, String signature,
			Label start, Label end, int index) {
		if (!needsInstrumentation && cv.isValueType(desc))
			needsInstrumentation = true;
		super.visitLocalVariable(name, desc, signature, start, end, index);
	}

	@Override
	public void visitMethodInsn(int opcode, String owner, String name,
			String desc) {
		if (!needsInstrumentation && cv.isValueType(owner))
			needsInstrumentation = true;
		super.visitMethodInsn(opcode, owner, name, desc);
	}

	@Override
	public void visitMultiANewArrayInsn(String desc, int dims) {
		if (!needsInstrumentation && cv.isValueType(desc))
			needsInstrumentation = true;
		super.visitMultiANewArrayInsn(desc, dims);
	}

	@Override
	public void visitTypeInsn(int opcode, String type) {
		if (!needsInstrumentation && cv.isValueType(type))
			needsInstrumentation = true;
		super.visitTypeInsn(opcode, type);
	}

}